<?php
	/**
	 * http通讯类
	 * detail description
	 * @todo Set-Cookie,gzip file decode
	 * @author swingcoder <swingcoder@msn.com>
	 * @version 0.1
	 * @copyright Copyright (c) 2009, swingcoder.com
	 */

	require_once 'socket.php';

	class http extends socket
	{
		public $target_url = '';
		private $in_charset = 'utf-8';
		private $out_charset = 'utf-8';
		private $cookie_str = '';
		private $http_method = 'get';
		public $response_charset = '';
		public $response_content_type = '';
		public $referer = '';

		function http($host, $in_charset='utf-8', $out_charset='utf-8', $timeout=30)
		{
			$this->in_charset = $in_charset;
			$this->out_charset = $out_charset;
			$this->parse_host($host);
			$this->socket($this->host, $this->port, $timeout);
		}

		function parse_host( $host )
		{
			$host = urldecode($host);
			$pathinfo = parse_url($host);
			$this->port = empty($pathinfo['port']) ? 80 : $pathinfo['port'];
			$pathinfo['path'] = empty($pathinfo['path']) ? '/' : $pathinfo['path'];
			$this->target_url = $pathinfo['path'] . (empty($pathinfo['query']) ? '' : '?' .  $this->encode_get_data($pathinfo['query']) );
			$this->host = $pathinfo['host'];
			$ip = gethostbyname( $this->host );
			if( ! $ip )
			{
				die('Can\'t not resolve the host name.');
			}

			return true;
		}

		function set_method( $method )
		{
			if( isset($method) )
			{
				$this->http_method = strtolower($method);
			}
			else
			{
				$this->http_method = strtolower(trim($_SERVER['REQUEST_METHOD']));
			}
		}

		function set_command($data='', $is_need_urlencode=true)
		{
			$method = $this->http_method;
			$this->cmd[] = $this->$method($data, $is_need_urlencode);
		}

		function get($data='', $is_need_urlencode=true)
		{
			$cmd = "GET ".$this->target_url." HTTP/1.1\r\n";
			$cmd .= "Host: ".$this->host."\r\n";
			$cmd .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)\r\n";
			$cmd .= "Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, application/x-shockwave-flash, */*\r\n";
			$cmd .= "Accept-Language: zh-cn,zh;q=0.5\r\n";
			//$cmd .= "Accept-Encoding: deflate\r\n";		//!! 访问http://milw0rm.com/webapps.php时用gzdeflate()解不开，故不能加此压缩声明
			$cmd .= "Accept-Charset: gb2312,utf-8,big5\r\n";
			if( ! empty($this->cookie_str) )
			{
				$cmd .= "Cookie: ".$this->cookie_str."\r\n";
			}
			$cmd .= "Referer: " . (empty($this->referer) ? 'http://' . $this->host : $this->referer) . "\r\n";
			$cmd .= "Connection: Close\r\n";
			$cmd .= "\r\n";

			return $cmd;
		}

		function post($data='', $is_need_urlencode=true)
		{
			$data = $this->encode_post_data($data, $is_need_urlencode);
			$cmd = "POST ".$this->target_url." HTTP/1.1\r\n";
			$cmd .= "Accept: */*\r\n";
			$cmd .= "Accept-Language: zh-cn\r\n";
			$cmd .= "Content-Type: application/x-www-form-urlencoded\r\n";
			$cmd .= "Accept-Encoding: deflate\r\n";
			$cmd .= "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Maxthon)\r\n";
			$cmd .= "Host: ".$this->host."\r\n";
			$cmd .= "Content-Length: ".strlen($data)."\r\n";
			$cmd .= "Connection: Close\r\n";
			$cmd .= "Cache-Control: no-cache\r\n";
			$cmd .= "Cookie: ".$this->cookie_str."\r\n";
			$cmd .= "\r\n" . $data;

			return $cmd;
		}

		function encode_get_data( $data_pair, $is_need_urlencode=true )
		{
			$ret = '';

			$urlinfo = explode('&', $data_pair);
			foreach($urlinfo as $keypair)
			{
				$key = substr($keypair, 0, strpos($keypair,'=') );
				$val  = substr($keypair, strpos($keypair,'=')+1);
				if( $this->in_charset != $this->out_charset )
				{
					$val = mb_convert_encoding($val, $this->out_charset, $this->in_charset);
				}
				$val = urlencode($val);
				$ret .= $key . '=' . $val . '&';
			}

			return substr($ret, 0, -1);
		}

		function encode_post_data( $data_pair, $is_need_urlencode=true )
		{
			$ret = '';

			$urlinfo = $data_pair;
			if( ! is_array($urlinfo) ) die('post data should be array');
			foreach($urlinfo as $key=>$val)
			{
				$val = ($is_need_urlencode == true ? urldecode($val) : $val);
				if( $this->in_charset != $this->out_charset )
				{
					$val = mb_convert_encoding($val, $this->out_charset, $this->in_charset);
				}
				$val = ($is_need_urlencode == true ? urlencode($val) : $val);
				if( is_numeric($key) )
				{
					$ret .= $val . '&';
				}
				else
				{
					$ret .= $key . '=' . $val . '&';
				}
			}

			return substr($ret, 0, -1);
		}

		function set_cookie( $arr )
		{
			if( is_array($arr) )
			{
				$str = '';
				foreach($arr as $key=>$val)
				{
					$str .= "$key=$val; ";
				}
				$str = substr($str, 0, -2);
			}
			else
			{
				$str = $arr;
			}
			$this->cookie_str = $str;
		}

		function write_response_cookie($cookie_arr)
		{
			$expire = time()+3600;
			$path = '/';
			$domain = $this->host;
			if( is_array($cookie_arr) )
			{
				foreach($cookie_arr as $cookie)
				{
					foreach($cookie as $idx=>$val)
					{
						if( strpos($val, '=') > 0 )
						{
							$t = explode('=', $val);
							${$t[0]} = $t[1];
							if( $idx == 0 )
							{
								$name = $t[0];
								$value = $t[1];
							}
						}
						setcookie($name, $value, $expire, $path, $domain);
					}
				}
			}
		}

		function set_referer( $referer )
		{
			$this->referer = $referer;
		}

		function parse_result( $result )
		{
			$header = substr($result, 0, strpos($result, "\r\n\r\n") );

			$t = $this->get_header_value('Content-type', $header);
			$this->response_content_type = strtolower( $t[0][0] );
			if( empty($this->response_content_type) )
			{
				$this->response_content_type = 'text/html';
			}
			if( count($t[0]) >= 2 )
			{
				$s = explode('=', $t[0][1]);
				$this->response_charset = strtolower($s[1]);
			}
			else
			{
				$html_header = substr($result, strpos($result, "charset=")+8, 18);
				$html_charset = substr($html_header, 0, strpos($html_header, "\""));
				$this->response_charset = strtolower($html_charset);
			}

			if( $this->response_charset == 'null' )
			{
				$this->response_charset = 'big5';
			}
			if( empty($this->response_charset) )
			{
				$this->response_charset = 'utf-8';
			}

			//$all_cookie_header = $this->get_header_value('Set-Cookie', $header);
			//$this->write_response_cookie($all_cookie_header);

			$jump_url = $this->check_http_status_code($header);
			if( substr($jump_url, 0, 3 ) == '302' )
			{
				return $jump_url;
			}
			elseif( substr($jump_url, 0, 1) == '4' )
			{
				die('抱歉：您请求的页面不存在。错误编号：s0001');
			}
			elseif( substr($jump_url, 0, 1) == '5' )
			{
				die('抱歉：您请求的网站发生内部错误。错误编号：s0002');
			}
			else
			{
				return substr($result, strpos($result,"\r\n\r\n")+4);
			}
		}

		function get_header_value( $name, $header )
		{
			$all_header = explode("\r\n", strtolower($header));
			$name = strtolower($name);
			$ret = array();
			if( $name == 'status' )
			{
				$t = explode(' ', $all_header[0]);
				$ret[] = array($t[1]);
				return $ret;
			}
			array_shift($all_header);
			foreach($all_header as $key=>$val)
			{
				$curr_header = substr($val, 0, strpos($val, ':') );
				if( strtolower($curr_header) == $name )
				{
					if( strpos($val, ';') >0 )
					{
						$ret[] = explode(';', trim(substr($val, strpos($val, ':') + 1 )) );
					}
					else
					{
						$ret[] = array(trim(substr($val, strpos($val, ':') + 1 )));
					}
				}
			}
			if( empty($ret) ){$ret[0] = array(''); $ret[1] = array('');}

			return $ret;
		}

		function check_http_status_code($header)
		{
			$http_status_code = $this->get_header_value('status', $header);
			if( $http_status_code[0][0] == '302' )	//HTTP/1.x 302 Moved Temporarily
			{
				$location = $this->get_header_value('Location', $header);
				if( strtolower(substr($location[0][0], 0, 4)) != 'http'  )
				{
						$location[0][0] = 'http://' . $this->host . ( (substr($location[0][0], 0, 1) == '/' ) ? '' : '/'  ) . $location[0][0];
				}
				return '302|' . $location[0][0];
			}
			else
			{
				return $http_status_code[0][0];
			}
		}

		function close()
		{
			if( is_resource($this->fp) ) fclose($this->fp);
		}

		function __destruct()
		{
			if( is_resource($this->fp) ) fclose($this->fp);
		}
	}
?>